<template>
  <div>
    <div class="text-xs text-end text-gray-400">shift + enter 换行</div>
    <div
      class="slate-ssml-editor-container mixed-tts-editor tts-preview-container tts-auto-split-container"
      :class="{ 'slate-text-warning': limit > 150 }"
      style="min-height: 150px; margin-top: 6px"
    >
      <div class="top-tooltip">
        <el-popover v-model:visible="pausePopover" placement="bottom" :width="200" trigger="click">
          <template #reference>
            <div
              class="top-button add-pause"
              aria-haspopup="true"
              aria-expanded="false"
              tabindex="0"
              aria-describedby="e4c13uj"
              data-popupid="e4c13uj"
            >
              <span class="top-button-ico ico-add-pause"></span>
              <span>插入停顿</span>
            </div>
          </template>
          <template #default>
            <div class="leading-9 cursor-pointer">
              <div @click="setPause('0.25s')">0.25s（较短）</div>
              <div @click="setPause('0.5s')">0.5s（短）</div>
              <div @click="setPause('1s')">1s（中）</div>
              <div @click="setPause('2s')">2s（长）</div>
            </div>
          </template>
        </el-popover>

        <div
          class="top-button set-mute"
          :class="{ disabled: !selectedText }"
          @click="setMute"
          tabindex="0"
          aria-describedby="wehoqgz"
          data-popupid="wehoqgz"
        >
          <span class="top-button-ico"></span>
          <span>取消诵读</span>
        </div>
        <el-popover
          v-model:visible="numberPopover"
          placement="bottom"
          :width="320"
          :disabled="!selectedText || !/^\d+$/.test(selectedText)"
          trigger="click"
        >
          <template #reference>
            <div
              class="top-button number-mark"
              :class="{
                disabled: !selectedText || !/^\d+$/.test(selectedText),
              }"
              tabindex="0"
              aria-describedby="orl17ox"
              data-popupid="orl17ox"
            >
              <span class="top-button-ico"></span>
              <span>数字读音</span>
            </div>
          </template>
          <template #default>
            <div class="leading-9 cursor-pointer">
              <div @click="setNumber('cardinal')">数字读法 (一百二十三万 一千两百三十四)</div>
              <div @click="setNumber('digits')">序列读法(一二三一二三四)</div>
              <div @click="setNumber('telephone')">电话读法(幺二三 幺二三四)</div>
            </div>
          </template>
        </el-popover>
        <el-popover
          v-model:visible="phonemePopover"
          placement="bottom"
          :width="290"
          :disabled="!selectedText || selectedText.length > 1"
          trigger="click"
          @show="showPopover"
        >
          <template #reference>
            <div
              class="top-button phoneme-mark"
              :class="{
                disabled: !selectedText || selectedText.length > 1,
              }"
              tabindex="0"
              aria-describedby="zqe8uqv"
              data-popupid="zqe8uqv"
            >
              <span class="top-button-ico"></span>
              <span>修改发音</span>
            </div>
          </template>
          <template #default>
            <div class="leading-7 cursor-pointer">
              <el-form ref="ruleFormRef" :rules="rules" :inline="true" :model="formInline">
                <el-form-item label="修改后" prop="text">
                  <el-space>
                    <el-input
                      ref="inputRef"
                      style="width: 120px"
                      autofocus
                      v-model="formInline.text"
                      placeholder=""
                      clearable
                    />
                    <el-button type="primary" @click="onSubmit(ruleFormRef)"> 确认 </el-button>
                  </el-space>
                </el-form-item>
                <div class="text-gray-400 text-xs">
                  1-4声拼音后面加1～4，轻声加5
                  <br />
                  例如：tian3
                </div>
              </el-form>
            </div>
          </template>
        </el-popover>
      </div>
      <div
        role="textbox"
        aria-multiline="true"
        :id="'slate-ssml-editor' + key"
        class="slate-ssml-editor text-limit"
        data-slate-editor="true"
        data-slate-node="value"
        contenteditable="true"
        zindex="-1"
        style="position: relative; outline: none; overflow-wrap: break-word"
      ></div>
      <div class="slate-ssml-editor-right-bottom-slot">
        <div class="tts-auto-split-btn-wrapper">
          <span>
            <div>
              <div class="slate-ssml-editor-text">{{ limit }}/150</div>
            </div>
          </span>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import type { FormInstance, FormRules } from "element-plus";
import { nextTick, onMounted, onUpdated, reactive, ref } from "vue";

const props = defineProps({
  innerHtml: {
    type: String,
    default: "",
  },
  tempContent: {
    type: Array,
    default: () => [],
  },
});

//获取一个随机数
let key = Math.random().toString(36).slice(2);

const emit = defineEmits(["update:tempContent", "update:innerHtml", "exceedLimit"]);
const selectedText = ref("");
const ruleFormRef = ref<FormInstance>();
const rules = reactive<FormRules>({
  text: [
    {
      required: true,
      validator: (rule, value, callback) => {
        if (!value) return callback(new Error("不能为空"));
        const reg = /^[a-zA-Z]+[1-5]$/;
        if (!reg.test(value)) {
          return callback(new Error("格式不正确"));
        } else {
          callback();
        }
      },
      trigger: "blur",
    },
  ],
});
const pausePopover = ref(false);
const numberPopover = ref(false);
const phonemePopover = ref(false);

const tempContent = ref<string[]>([]);
const innerHtml = ref("");
const inputRef = ref();
const formInline = reactive({
  text: "",
});
const limit = ref(0);

const showPopover = () => {
  //聚焦到 input 上
  inputRef.value?.focus();
};
let range: Range | null = null;

//插入停顿
const setPause = (time: string) => {
  // 创建停顿图标
  const pauseMarker = `<span
      class="pause-element-wrapper"
      contenteditable="false"
    >
      <span
        class="element-node"
      >
        <span class="element-ico"></span>
        <span>${time}</span>
      </span>
    </span>`;

  if (range) {
    // 插入停顿标记到鼠标点击位置
    const node = document.createRange().createContextualFragment(pauseMarker);
    addClickEvent(node);
    range!.insertNode(node);
    pausePopover.value = false;
  }
};
//静音
const setMute = () => {
  if (!selectedText.value) return;
  if (range) {
    // 删除选中文本
    range.deleteContents();
    // 插入取消朗读图标到选中文本的后面
    range.collapse(false); // 将范围折叠到结束点

    // 添加下划线样式
    const underlinedText = document.createElement("span");
    underlinedText.setAttribute("contenteditable", "false");
    underlinedText.setAttribute("data-slate-node", "text");
    underlinedText.innerHTML = selectedText.value;
    underlinedText.classList.add("m_underline");

    // 创建取消朗读图标
    const str = `<span
        class="mute-element-wrapper"
        contenteditable="false"
      >${underlinedText.outerHTML}<span
          class="mute-element-tag"
          tabindex="0"
        ><span class="element-ico"></span></span></span>`;
    const node = document.createRange().createContextualFragment(str);
    // 把span插入到node里面
    addClickEvent(node);

    range.insertNode(node);

    // range.insertNode(underlinedText);
  }
};

//数字读音
const setNumber = (type: string) => {
  if (range) {
    // 删除选中文本
    range.deleteContents();
    // 插入取消朗读图标到选中文本的后面
    range.collapse(false); // 将范围折叠到结束点

    // 添加下划线样式
    const underlinedText = document.createElement("span");
    underlinedText.innerHTML = selectedText.value;
    underlinedText.classList.add("n_underline", "number-element-wrapper");
    underlinedText.setAttribute("contenteditable", "false");
    underlinedText.setAttribute("data-interpret-as", type);
    underlinedText.addEventListener("click", (e: Event) => {
      e.stopPropagation();
      //获取当前点击的元素
      const target = e.target as HTMLElement;
      const wrapperElement = target.closest(".number-element-wrapper");
      wrapperElement?.classList.remove("n_underline");
      wrapperElement?.classList.remove("number-element-wrapper");
      wrapperElement?.setAttribute("data-interpret-as", "");
      wrapperElement?.setAttribute("contenteditable", "true");
    });
    range.insertNode(underlinedText);

    numberPopover.value = false;
  }
};

// 获取当前选中的文本
function getSelectedText() {
  try {
    if (window.getSelection) {
      range = window.getSelection()!.getRangeAt(0);
      return window.getSelection()!.toString();
    } else if ((document as any).selection && (document as any).selection.type !== "Control") {
      return (document as any).selection.createRange().text;
    }
    return "";
  } catch (error) {}
}

//确认修改发音
const onSubmit = async (formEl: FormInstance | undefined) => {
  if (!formEl) return;
  await formEl.validate((valid, fields) => {
    if (valid) {
      if (range) {
        // 删除选中文本
        range.deleteContents();
        // 插入取消朗读图标到选中文本的后面
        range.collapse(false); // 将范围折叠到结束点
        // 添加下划线样式
        const underlinedText = document.createElement("span");
        underlinedText.setAttribute("contenteditable", "false");
        underlinedText.setAttribute("data-py", formInline.text);
        underlinedText.innerHTML = selectedText.value;
        underlinedText.classList.add("r_underline");
        const str = `<span class="phoneme-element-wrapper" contenteditable="false">${underlinedText.outerHTML}<a class="phoneme-element-tag">${formInline.text}</a></span>`;
        const node = document.createRange().createContextualFragment(str);
        addClickEvent(node);
        range.insertNode(node);
        phonemePopover.value = false;
        formInline.text = "";
      }
    } else {
      console.log("error submit!", fields);
    }
  });
};

//把 id slate-ssml-editor的div的内容转换成数组
const getContent = async () => {
  await nextTick();

  const editor = document.getElementById(`slate-ssml-editor${key}`)!;

  // 获取 editor 下 所有的 cus-slate-section 元素
  const pElements = editor.querySelectorAll(`.cus-slate-section${key}`);

  // 用于存储所有文本内容的数组
  const allTextContentArray: string[] = [];

  // 递归函数，用于查找带有 mute-element-wrapper 类的元素并提取文本内容
  function findMuteElement(node: any) {
    // 如果节点是文本节点，直接返回其内容
    if (node.nodeType === Node.TEXT_NODE) {
      return node.textContent.trim();
    }

    //如果是 <br /> 标签 追加 \n
    if (node.nodeType === Node.ELEMENT_NODE) {
      if (node.tagName.toLowerCase() === "br") {
        return "\n";
      }
    }

    // 如果节点是 span 元素
    if (node.nodeType === Node.ELEMENT_NODE && node.tagName.toLowerCase() === "span") {
      // 如果是带有 mute-element-wrapper 类的 span 元素
      if (node.classList.contains("mute-element-wrapper")) {
        // 获取 mute-element-wrapper 内的文本内容，使用正则表达式过滤空白字符
        const wrapperText = Array.from(node.childNodes)
          .filter((childNode: any) => childNode.nodeType === Node.ELEMENT_NODE)
          .map(
            (textNode: any) => textNode.textContent.trim().replace(/\s+/g, " ") // 去除多余的空白字符
          )
          .join("");
        // 使用 <sub alias=""></sub> 包裹文本内容，并返回
        return `<sub alias=" ">${wrapperText}</sub>`;
      }
      //修改发音
      else if (node.classList.contains("phoneme-element-wrapper")) {
        // 获取 mute-element-wrapper 内的文本内容，使用正则表达式过滤空白字符
        let py = "";
        const wrapperText = Array.from(node.childNodes)
          .filter((childNode: any) => {
            py = node.querySelector("a")?.textContent;
            // 过滤掉a标签
            return (
              childNode.nodeType === Node.ELEMENT_NODE && childNode.tagName.toLowerCase() !== "a"
            );
          })
          .map(
            (textNode: any) => textNode.textContent.trim().replace(/\s+/g, " ") // 去除多余的空白字符
          )
          .join("");
        return `<phoneme alphabet="py" ph="${py}">${wrapperText}</phoneme>`;
      } else if (node.classList.contains("number-element-wrapper")) {
        // 获取 mute-element-wrapper 内的文本内容，使用正则表达式过滤空白字符
        let interpretAs = "";
        const wrapperText = Array.from(node.childNodes)
          .filter((childNode: any) => {
            interpretAs = node.getAttribute("data-interpret-as");
            return childNode.nodeType === Node.TEXT_NODE;
          })
          .map(
            (textNode: any) => textNode.textContent.trim().replace(/\s+/g, " ") // 去除多余的空白字符
          )
          .join("");
        return `<say-as interpret-as="${interpretAs}">${wrapperText}</say-as>`;
      } else if (node.classList.contains("pause-element-wrapper")) {
        // 获取 mute-element-wrapper 内的文本内容，使用正则表达式过滤空白字符
        let ms = 0;
        ms = node.innerText.trim().replace("s", "") * 1000;
        return `<break time="${ms}ms"/>`;
      }
    }

    // 如果不是目标元素，继续递归查找子节点
    let result = "";
    for (const childNode of node.childNodes) {
      result += findMuteElement(childNode);
    }

    return result;
  }
  // 遍历每个 p 元素
  pElements.forEach((pElement) => {
    // 用于存储当前 p 元素文本内容的数组
    const textContentArray = [];

    // 遍历 p 元素的子节点
    for (const node of pElement.childNodes) {
      const result = findMuteElement(node);
      textContentArray.push(result);
    }

    // 将当前 p 元素的文本内容添加到总数组中
    const concatenatedText = textContentArray.filter((e) => e !== "\n").join("");
    concatenatedText && allTextContentArray.push(`<speak>${concatenatedText}</speak>`);
  });

  tempContent.value = allTextContentArray;
  console.log(tempContent.value);
  emit("update:tempContent", allTextContentArray);
  //把 editor 里面的内容转换成字符串
  innerHtml.value = editor.innerHTML;
  emit("update:innerHtml", editor.innerHTML);
};

//添加点击事件
const addClickEvent = (node: DocumentFragment) => {
  //静音
  node.querySelectorAll(".mute-element-wrapper")!.forEach((item) => {
    item.addEventListener("click", (e: Event) => {
      e.stopPropagation();
      //获取当前点击的元素
      const target = e.target as HTMLElement;
      const wrapperElement = target.closest(".mute-element-wrapper");
      //找到 mute-element-wrapper 中的 带有 m_underline 类名的元素
      const sibling = wrapperElement?.querySelector(".m_underline") as HTMLElement;
      //把siblings的类名 m_underline 移除
      sibling?.classList.remove("m_underline");
      //把siblings的属性 contenteditable 设置为 true
      sibling?.setAttribute("contenteditable", "true");
      //把 sibling 插入到 mute-element-wrapper 的前面
      wrapperElement?.insertAdjacentElement("beforebegin", sibling);
      //把 mute-element-wrapper 删除
      wrapperElement?.remove();
    });
  });
  //数字读音
  node.querySelectorAll(".number-element-wrapper")!.forEach((item) => {
    item.addEventListener("click", (e: Event) => {
      e.stopPropagation();
      //获取当前点击的元素
      const target = e.target as HTMLElement;
      const wrapperElement = target.closest(".number-element-wrapper");
      wrapperElement?.classList.remove("n_underline");
      wrapperElement?.classList.remove("number-element-wrapper");
      wrapperElement?.setAttribute("contenteditable", "true");
      wrapperElement?.setAttribute("data-interpret-as", "");
      getContent();
    });
  });
  //停顿
  node.querySelectorAll(".pause-element-wrapper")!.forEach((item) => {
    item.addEventListener("click", (e: Event) => {
      e.stopPropagation();
      //获取当前点击的元素
      const target = e.target as HTMLElement;
      const wrapperElement = target.closest(".pause-element-wrapper");
      wrapperElement?.remove();
    });
  });

  //修改发音
  node.querySelectorAll(".phoneme-element-wrapper")!.forEach((item) => {
    item.addEventListener("click", (e: Event) => {
      e.stopPropagation();
      //获取当前点击的元素
      const target = e.target as HTMLElement;
      const wrapperElement = target.closest(".phoneme-element-wrapper");
      //找到 phoneme-element-wrapper 中的 带有 r_underline 类名的元素
      const sibling = wrapperElement?.querySelector(".r_underline") as HTMLElement;
      //把siblings的类名 r_underline 移除
      sibling?.classList.remove("r_underline");
      //把siblings的属性 contenteditable 设置为 true
      sibling?.setAttribute("contenteditable", "true");
      sibling?.setAttribute("data-py", "");
      //把 sibling 插入到 mute-element-wrapper 的前面
      wrapperElement?.insertAdjacentElement("beforebegin", sibling);
      //把 mute-element-wrapper 删除
      wrapperElement?.remove();
    });
  });
};

//监听 id 为 slate-ssml-editor的div选中文字事件
onMounted(() => {
  const editor = document.getElementById(`slate-ssml-editor${key}`)!;
  // 监听选择文本的变化
  editor.addEventListener("mouseup", (e: any) => {
    setTimeout(() => {
      selectedText.value = getSelectedText();
    }, 0);
  });

  // 监听键盘按下事件
  document.addEventListener("keydown", (event) => {
    if (event.key === "Escape") {
      selectedText.value = "";
    }

    //如果按下的是 enter 键
    if (event.key === "Enter") {
      // 获取当前选区
      const selection = window.getSelection();

      // 确保存在选区并且选区范围大于 0
      if (selection && selection.rangeCount > 0) {
        // 获取选区的第一个范围
        range = selection.focusNode ? selection.getRangeAt(0) : document.createRange();
      }
    }

    //如果按下的是  shift + enter 键
    if (event.key === "Enter" && event.shiftKey) {
      // event.preventDefault();
    }

    //如果按下的是  backspace 键
    if (event.key === "Backspace") {
      //如果只存在一个cus-slate-section 元素
      if (editor.querySelectorAll(`.cus-slate-section${key}`).length === 1) {
        //如果cus-slate-section 元素里面没有文本内容
        if (editor.querySelector(`.cus-slate-section${key}`)!.textContent === "") {
          event.preventDefault();
        }
      }
    }
  });

  // 监听paste事件
  editor.addEventListener("paste", (event) => {
    event.preventDefault();
    const pastedText = event.clipboardData?.getData("text/plain")!;

    // 创建一个新的span标签，将粘贴的文本添加到其中

    const underlinedText = document.createElement("span");

    underlinedText.innerHTML = pastedText;

    //获取光标所在的位置
    const selection = window.getSelection();
    if (selection && selection.rangeCount > 0) {
      // 获取选区的第一个范围
      range = selection.focusNode ? selection.getRangeAt(0) : document.createRange();
    }

    //插入到鼠标点击的位置
    if (range) {
      range.insertNode(underlinedText);
    }
  });
  // 监听用户点击输入框事件
  editor.addEventListener("mousedown", () => {
    try {
      selectedText.value = getSelectedText();
    } catch (error) {}
  });

  // 监听editor dom变化
  editor.addEventListener("DOMSubtreeModified", () => {
    getContent();
    wordCount();
  });
  renderContent();
});

//把 pros.tempContent的内容渲染到id slate-ssml-editor的div
const renderContent = async () => {
  await nextTick();
  const editor = document.getElementById(`slate-ssml-editor${key}`)!;
  if (props.innerHtml) {
    // 从props.innerHtml中找出key 在slate-ssml-editor 字符串 后面
    const regex = /class="cus-slate-section([^"]*)"/g;
    key = regex.exec(props.innerHtml)![1];

    const node = document.createRange().createContextualFragment(props.innerHtml || "");
    addClickEvent(node);
    //清空 editor 里面的内容
    editor.innerHTML = "";
    editor.appendChild(node);
  } else {
    const str = `<p class="cus-slate-section${key}" data-slate-node="text">
            <span data-slate-node="text">&#xFEFF</span>
          </p>`;
    const node = document.createRange().createContextualFragment(str);
    //清空 editor 里面的内容
    editor.innerHTML = "";
    editor.appendChild(node);

    //聚焦在 span 元素上
    const spanElement = editor.querySelector('span[data-slate-node="text"]');
    const range = document.createRange();
    range.setStart(spanElement!, 0);
  }
};

//计算字数
const wordCount = () => {
  // 获取 id   所有的 cus-slate-section 元素
  const cusSlateSections = document.querySelectorAll(`.cus-slate-section${key}`);

  // 计算文字数量的递归函数
  function countTextNodes(node: any) {
    let textCount = 0;

    // 遍历节点的子节点
    for (const childNode of node.childNodes) {
      // 如果子节点是元素节点，且不含有 pause-element-wrapper 或 phoneme-element-tag 类
      if (
        childNode.nodeType === Node.ELEMENT_NODE &&
        !childNode.classList.contains("pause-element-wrapper") &&
        !childNode.classList.contains("phoneme-element-tag")
      ) {
        // 递归计算其文字数量
        textCount += countTextNodes(childNode);
      }
      // 如果子节点是文本节点，累加文字数量
      else if (childNode.nodeType === Node.TEXT_NODE) {
        textCount += childNode.textContent.trim().length;
      }
    }

    return textCount;
  }

  limit.value = 0;
  // 计算所有 cus-slate-section 元素下的文字数量（过滤掉特定类的节点）
  cusSlateSections.forEach((cusSlateSection) => {
    const textCount = countTextNodes(cusSlateSection);
    limit.value += textCount;
  });
  emit("exceedLimit", limit.value > 150);
};

defineExpose({
  getContent,
  renderContent,
});
</script>

<style lang="scss">
.m_underline,
.n_underline,
.r_underline {
  position: relative;
  display: inline-block;
}
.m_underline::after,
.n_underline::after,
.r_underline::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 2px; /* 下划线高度 */
  display: block;
}
.m_underline::after {
  background-color: #572fb3;
}
.n_underline::after,
.r_underline::after {
  background-color: #d26700;
}
</style>
